package com.apes.scm.rbac.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.generator.service.SequenceService;
import com.apes.framework.jpa.logger.ApesLoggerService;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.jpa.spec.model.Group;
import com.apes.framework.plugin.cache.Cache;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.event.Listener;
import com.apes.framework.plugin.express.FuncAlias;
import com.apes.framework.plugin.mq.MQUtil;
import com.apes.framework.plugin.mq.annotation.Consumer;
import com.apes.framework.plugin.websocket.WsMessage;
import com.apes.framework.plugin.websocket.WsPublisher;
import com.apes.framework.rop.securityManager.SampleSessionManager;
import com.apes.framework.rop.session.SessionUtil;
import com.apes.framework.rop.session.SimpleSession;
import com.apes.framework.rop.session.index.SessionIndexItem;
import com.apes.framework.rop.session.index.SessionIndexManager;
import com.apes.framework.util.*;
import com.apes.hr.base.model.WorkPost;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.enumeration.repository.EnumerationRepository;
import com.apes.scm.masterdata.frame.model.Contacts;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.frame.model.Store;
import com.apes.scm.masterdata.frame.repository.ContactsRepository;
import com.apes.scm.masterdata.frame.repository.DeptRepository;
import com.apes.scm.masterdata.frame.repository.StoreRepository;
import com.apes.scm.masterdata.party.model.AccessProvider;
import com.apes.scm.masterdata.party.model.Party;
import com.apes.scm.masterdata.party.model.PartyIdentification;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.AccessProviderRepository;
import com.apes.scm.masterdata.party.repository.PartyIdentificationRepository;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.masterdata.stock.model.Location;
import com.apes.scm.masterdata.stock.repository.DepotRepository;
import com.apes.scm.masterdata.stock.repository.LocationRepository;
import com.apes.scm.rbac.model.*;
import com.apes.scm.rbac.repository.LocalPermitRepository;
import com.apes.scm.rbac.repository.PersonalMenuMarkRepository;
import com.apes.scm.rbac.repository.PostRepository;
import com.apes.scm.rbac.repository.UserRepository;
import org.apache.commons.lang.RandomStringUtils;
import org.hibernate.SQLQuery;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;


/**
 * 功能：用户服务
 *
 * @author xul
 * @create 2017-12-13 16:57
 */
@Controller
public class UserService extends DomainService {
    private final String CONST_MENU_AUTH_CACHE = "menuAuthCache";
    private final String CONST_TV_TOKEN_CACHE = "authTvTokenCache";

    @Value("${apes.sso.enabled:false}")
    private boolean ssoEnabled;

    @Autowired
    private LocationRepository locationRepository;

    @Autowired
    private DeptRepository deptRepository;

    @Autowired
    private PartyRoleRepository partyRoleRepository;

    @Autowired
    private Cache cache;

    @Autowired
    UserRepository userRepository;

    @Autowired
    DepotRepository depotRepository;

    @Autowired
    private StoreRepository storeRepository;

    @Autowired
    private LocalPermitRepository localPermitRepository;


    @Autowired
    private PostRepository postRepository;

    @Autowired
    private EnumerationRepository enumerationRepository;

    @Autowired
    PartyIdentificationRepository partyIdentificationRepository;

    @Autowired
    ApesLoggerService apesLoggerService;

    @Autowired
    private ContactsRepository contactsRepository;

    @Autowired
    PersonalMenuMarkRepository personalMenuMarkRepository;

    /**
     * 功能：通过ID查找用户
     *
     * @param request
     * @return
     */
    public User findUserById(SimpleRequest request) {
        User user = userRepository.findOne(Integer.valueOf(request.get("id")));
        Assert.notNull(user, "用户：" + request.get("id") + " 在系统中不存在。");
        return user;
    }


    /*
     * 创建、更新
     * */
    public User save(SimpleRequest request) {
        User user = request.getO(User.class);
        // 默认 123456的md5 密码
        String password = Optional.ofNullable(user.getPassword()).orElse("e10adc3949ba59abbe56e057f20f883e");
        if (user.getAccessId() == null) { // 新建时
            // 公钥 操作员账号 + 随机字符串 加密
            String accessId = user.getOrigin() + ":" + RandomStringUtils.randomAlphanumeric(10);
            user.setAccessId(accessId);
            // 私钥
            String accessKey = MD5Util.encrypt(RandomStringUtils.randomAlphanumeric(16));
            user.setAccessKey(accessKey);
            // 私钥有效期止
            updateUserValidityTime(user, LocalDateTime.now().plusYears(1));
        }

        user.setPassword(password);
        // user.setPassword(MD5Util.encrypt(request.get("password")));

        // 添加中间表信息
        List<JSONObject> postLists = user.getPostLits();
        if (postLists != null) {
            List<Post> posts = new ArrayList<>();
            postLists.stream().forEach(
                    (postJ) -> {
                        Post post = postRepository.findOne(postJ.getString("id"));
                        posts.add(post);
                    }
            );
            user.setPosts(posts);
        }
        //查询数据库是否禁用进行对比，发生改变进行写入日志
        if (user.getId() != null) {
            User temp = userRepository.findOne(user.getId());
            if (user.isDisable() != temp.isDisable()) {
                if (user.isDisable()) {
                    SimpleSession session = request.getSession();
                    apesLoggerService.sendSynEvent("event:ir.logger.create", MapUtil.mapper("businessType", "User",
                            "businessKey", user.getId(), "operate", "禁用角色", "workPostName",null,  "operator_id", 1));
                } else {
                    apesLoggerService.sendSynEvent("event:ir.logger.create", MapUtil.mapper("businessType", "User",
                            "businessKey", user.getId(), "operate", "启用角色", "workPostName",null, "operator_id", 1));
                }
            }
        }

        User result = userRepository.saveAndFlush(user);
        result.setPostLits(user.getPostLits());
        if (result.getPerson()!= null)
            result.getPerson().setId(result.getOrigin());
        return result;
    }

    private void updateUserValidityTime(User user, LocalDateTime localDateTime) {
        LocalDateTime dateTime = localDateTime;
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = dateTime.atZone(zoneId);
        Date date = Date.from(zdt.toInstant());
        user.setValidityTime(date);
    }

    public String delete(SimpleRequest request) {
        int id = request.get("id");
        User user = userRepository.findOne(id);
        userRepository.delete(user);
        return "删除成功！";
    }


    /*
     * 定义操作员 数据格式化给前端
     * */
    public Page<User> findAllForUi(SimpleRequest request) {
        Page<User> userPage = request.getO(Page.class);
        userPage.getContent().stream().forEach(
                (user) -> {
                    List<Post> posts = user.getPosts();
                    if (posts != null) {
                        List postsLists = new ArrayList();
                        posts.stream().forEach(
                                (post) -> {
                                    JSONObject postJo = new JSONObject();
                                    postJo.put("id", post.getId());
                                    postJo.put("name", post.getName());
                                    postsLists.add(postJo);
                                }
                        );
                        user.setPostLits(postsLists);
                    }
                }
        );
        return userPage;
    }


    /*
     * 同步
     * */
    public User synchronous(User user) {
        user.setPassword(MD5Util.encrypt(user.getPassword()));
        userRepository.save(user);
        return user;
    }

    //http://localhost:8060/router?appKey=00001&body={"name":"CZY0001","password":"1234","roles":[{"id":"00123"}]}&method=user.login&version=1.0

    /**
     * 功能：通过Name查找用户
     *
     * @param request
     * @return
     */
    public Map login(SimpleRequest request) {
        Map m = request.getMap();
        String userId = (String) m.get("userId");
        User user = getUser(userId);
        Assert.isTrue(!user.isDisable(), "该用户已禁用");
        String password = MD5Util.encrypt(request.get("password"));
        Assert.isTrue(user.getPassword().equalsIgnoreCase(password), "请输入合法密码。");
        return loginCore(request, user, null);
    }


    /***
     * 免密登录
     * @param request
     * @return
     */
    public Map loginIgnorePassword(SimpleRequest request) {
        Map req = request.getMap();
        // 获取当前人员
        String userId = request.get("userId");
        User user = getUser(userId);
        if (req.get("accessKey") != null && !req.get("accessKey").equals(user.getAccessKey())) {
            throw new RuntimeException("用户信息已变更，请重新登陆！");
        }

        // 禁用已被禁止的人员
        Assert.isTrue(!user.isDisable(), "该用户已禁用");

        // 获取岗位
        Post post;
        if (req.get("post") != null) {
            post = request.getO("post", Post.class);
        } else {
            List<Post> posts = invoke("aut.user.getPosts", MapUtil.mapper("userId", request.get("userId")));
            if (posts == null && posts.size() == 0) throw new RuntimeException("请定义该角色对应的岗位信息");
            post = posts.get(0);
        }
        return loginCore(request, user, post);
    }


    private Map loginCore(SimpleRequest request, User user, Post post) {
        Map reqDate = request.getMap();
        if(post == null && reqDate.get("post") == null) throw new RuntimeException("当前操作员无本地角色，可联系行政主管配置本地角色");
        String postId = post != null ? post.getId() : (String) ((Map) reqDate.get("post")).get("id");
        Post matchPost = user.getPosts().stream().filter(item -> item.getId().equals(postId)).findFirst().orElse(null);
        Assert.notNull(matchPost, "岗位ID：" + postId + " 输入错误。ErrorCode(1013)");

        List<SessionIndexItem> sessionIndexItems = (List<SessionIndexItem>) getBean(SessionIndexManager.class).get(user.getId());
        if (sessionIndexItems == null) sessionIndexItems = new ArrayList<>();

        if (ssoEnabled) { /**单点登录**/
            String hash = (String) reqDate.get("hash");
            String terminal = (String) reqDate.get("terminal");
            if (!StringUtils.isEmpty(terminal) && !StringUtils.isEmpty(hash)) {
                WsMessage wsMessage = new WsMessage();
                wsMessage.setTo(String.valueOf(user.getId()));
                wsMessage.setBody(JSON.toJSONString(MapUtil.mapper("topic", "ws.client.sso", "terminal", terminal, "hash", hash)));
                wsPublisher.publish(wsMessage);
            }
        }

        String sessionId = SessionUtil.getSessionId(String.valueOf(user.getId()), String.valueOf(new Date().getTime()));
        SimpleSession session = new SimpleSession();
        session.setUser(String.valueOf(user.getId()), user.getName());
        session.setIp(request.getRopRequestContext().getIp());
        session.setSessionId(sessionId);
        setPost(session, matchPost);
        request.getRopRequestContext().addSession(sessionId, session);

        SessionIndexItem sessionIndexItem = new SessionIndexItem();
        sessionIndexItem.setSessionId(sessionId);
        sessionIndexItem.setPostId(matchPost.getId());
        sessionIndexItems.add(sessionIndexItem);
        getBean(SessionIndexManager.class).add(user.getId(), sessionIndexItems);

        updateUserValidityTime(user, LocalDateTime.now().plusMonths(6)); /**每次登陆将有效期往后推半年**/

        setAccessProvider(user);
        setQXEpcDept(user);
        Map m = MapUtil.mapped(user);
        m.remove("password");
        return MapUtil.mapper("sessionId", sessionId, "user", m);
    }

    private static final HashMap<String, Map> accessProviders = new HashMap();

    private void setAccessProvider(User user) {
        for (Post post : user.getPosts()) {
            Map accessProviderMap = null;
            String postId = post.getId();
            if (accessProviders.containsKey(postId)) {
                accessProviderMap = accessProviders.get(postId);
            } else {
                if (post.getCompany() != null) {
                    AccessProvider accessProvider = SpringManager.getBean(AccessProviderRepository.class).findByCompany(post.getCompany().getId());
                    if (accessProvider != null) {
                        accessProviderMap = MapUtil.mapped(accessProvider);
                    }
                }
                accessProviders.put(postId, accessProviderMap);
            }
            if (accessProviderMap != null) post.setAccessProvider(accessProviderMap);
        }
    }

    private static final HashMap<String, Boolean> epcFlags = new HashMap();

    private void setQXEpcDept(User user) {
        for (Post post : user.getPosts()) {
            String postId = post.getId();
            if (epcFlags.containsKey(postId)) {
                post.setQxEPCDeptFlag(epcFlags.get(postId));
            } else {
                if (post.getDept() != null) {
                    Boolean flag = obtainEpcInfo(post.getDept().getId());
                    epcFlags.put(postId, flag);
                    post.setQxEPCDeptFlag(flag);
                }
            }
        }
    }

    private Boolean obtainEpcInfo(String id) {
        Map newMap = new HashMap();
        newMap.put("deptId", id);
        String notifyTopic = "event:pi.epc.synEpcNotify";
        return (Boolean) (EventUtil.sendSynEvent(this, notifyTopic, newMap).stream().findFirst().get());
    }

    private void setPost(SimpleSession session, Post post) {
        session.setPostId(post.getId());
        session.setBranchId(post.getBranch().getId());
        session.setCompanyId(post.getCompany().getParty().getId());

        WorkPost workPost = post.getWorkPost();
        if (workPost != null) {
            session.setAttribute("workPostId", workPost.getId());
            session.setAttribute("workPostName", workPost.getName());
        }
    }


    @Autowired
    private WsPublisher wsPublisher;

    public Map loginTV(SimpleRequest request) throws Exception {
        String userId = request.get("wsId");

        Map resultMap = MapUtil.mapped(login(request));        // 调用登录方法
        resultMap.put("topic", "ws.loginTV");

        // 获取当前的post
        String postId = (String) ((Map) request.get("post")).get("id");
        Post post = getPosts(request).stream()
                .filter(item -> item.getId().equals(postId))
                .findFirst().get();
        Map postMap = new HashMap();
        postMap.put("post", post);
        Map m = MapUtil.mapped(postMap);

        Map userMap = (Map) resultMap.get("user");
        userMap.put("post", m.get("post"));
        userMap.put("sessionId", resultMap.get("sessionId"));

        // 发送 webSocket 消息
        if (userId != null && !"".equals(userId)) {
            WsMessage wsMessage = new WsMessage();
            wsMessage.setTo(userId);
            wsMessage.setBody(JSON.toJSONString(resultMap));
            wsPublisher.publish(wsMessage);
        }

        Map token = (Map<String, Object>) cache.get(CONST_TV_TOKEN_CACHE, userId);
        if (token != null) {
            token.put("login", true);
            token.put("user", resultMap);
            cache.put(CONST_TV_TOKEN_CACHE, token.get("tokenId").toString(), token);
        }

        return userMap;
    }

    public Map saveTvToken(SimpleRequest request) {
        Map token = request.getMap();
        token.put("login", false);
        token.put("time", new Date());
        cache.put(CONST_TV_TOKEN_CACHE, token.get("tokenId").toString(), token);
        return token;
    }

    public Map<String, Object> getTvToken(SimpleRequest request) {
        String tokenId = request.get("tokenId");
        Map token = (Map<String, Object>) cache.get(CONST_TV_TOKEN_CACHE, tokenId);
        if (token != null && (boolean) token.get("login")) {
            cache.remove(CONST_TV_TOKEN_CACHE, tokenId);
        }
        return token;
    }

    public User getUser(String userId) {
        User user = userRepository.findByOrigin(userId);
        if (user == null) {
            try {
                Integer id = Integer.valueOf(userId);
                user = userRepository.findOne(id);
            } catch (Exception e) {
                throw new RuntimeException("用户：" + userId + " 输入错误。");
            }
        }
        Assert.notNull(user, "用户：" + userId + " 在系统中不存在。");
        return user;
    }

    public List<Post> getPosts(SimpleRequest request) {
        String userId = request.get("userId");
        User user = userRepository.findByOrigin(userId);
        if(user == null) throw new RuntimeException("用户：" + userId + " 在系统中不存在。");
        setAccessProvider(user);
        setQXEpcDept(user);
        return user.getPosts();
    }

    public List<Map> bindPost(SimpleRequest request) {
        SimpleSession session = getSession(request);
        String terminal = (String) request.getMap().get("terminal");
        String postId = (String) ((Map) request.get("post")).get("id");
        if (Tools.isNull(session.getPostId()) || !session.getPostId().equals(postId)) {
            User user = getUser(session.getUserId());
            Post post = user.getPosts().stream().filter(item -> item.getId().equals(postId)).findFirst().get();
            Assert.notNull(post, "岗位ID：" + postId + " 输入错误。ErrorCode(1013)");
            setPost(session, post);
        }
        List<SessionIndexItem> sessionIndexItems = (List<SessionIndexItem>) getBean(SessionIndexManager.class).get(Integer.valueOf(session.getUserId()));
        if (sessionIndexItems != null) {
            sessionIndexItems.stream().filter(item -> item.getSessionId().equals(session.getSessionId())).forEach(item -> item.setPostId(postId));
            getBean(SessionIndexManager.class).add(Integer.valueOf(session.getUserId()), sessionIndexItems);
        }
        return getMenus(postId, terminal);
    }

    @Autowired
    MenuService menuService;

    public List<Map> getMenu(SimpleRequest request) {
        SimpleSession session = getSession(request);
        String terminal = (String) request.getMap().get("terminal");
        String postId;
        if (request.getMap().containsKey("postId")) {
            postId = request.get("postId");
        } else {
            Assert.notNull(session, "请重新登陆！");
            postId = session.getPostId();
        }
        Assert.notNull(postId, "岗位错误。");
        return getMenus(postId, terminal);
    }

    private List<Map> getMenus(String postId, String terminal) {
        Post post = getBean(PostRepository.class).findOne(postId);
        Map<String, List<Map>> terminals = getMenuAuth(postId);
        if (terminals == null) terminals = new HashMap<>();
        if (!terminals.containsKey(terminal)) {
            List<Map> menus = menuService.getMenus(post.findMenus(terminal));
            List<Map> menuAuth = MapUtil.mapped(menus);
            terminals.put(terminal, menuAuth);
            addMenuAuth(postId, terminals);
        }
        return terminals.get(terminal);
    }

    private void addMenuAuth(String postId, Map<String, List<Map>> terminals) {
        cache.put(CONST_MENU_AUTH_CACHE, postId, terminals);
    }

    private Map<String, List<Map>> getMenuAuth(String postId) {
        return (Map<String, List<Map>>) cache.get(CONST_MENU_AUTH_CACHE, postId);
    }

    public void removeMenuAuth(String postId) {
        cache.remove(CONST_MENU_AUTH_CACHE, postId);
    }

    public void logout(SimpleRequest request) {
        SimpleSession session = getSession(request);
        if (session == null) return;
        removeSession(session);
    }

    private void removeSession(SimpleSession session) {
        getBean(SampleSessionManager.class).removeSession(session.getSessionId());
        Integer userId = Integer.valueOf(session.getUserId());
        List<SessionIndexItem> sessionIndexItems = (List<SessionIndexItem>) getBean(SessionIndexManager.class).get(userId);
        if (sessionIndexItems != null) {
            Iterator<SessionIndexItem> iterator = sessionIndexItems.iterator();
            while (iterator.hasNext()) {
                SessionIndexItem item = iterator.next();
                if (item.getSessionId().equals(session.getSessionId())) {
                    iterator.remove();
                }
            }
            if (sessionIndexItems.isEmpty()) getBean(SessionIndexManager.class).remove(userId);
            else getBean(SessionIndexManager.class).add(userId, sessionIndexItems);
        }
    }

    /***
     * 功能： 修改密码
     * @param request
     * @return
     */
    public User updatePassword(SimpleRequest request) {

        JSONObject tempJson = request.getJO();
        User user = userRepository.findByOrigin(tempJson.getString("origin"));
//        if (user == null) throw new RuntimeException("未找到对应的操作员");
        if (user == null) return null;  // 暂时屏蔽未找到对应的操作员的报错

//      针对目前所有新旧系统密码可能不一致的问题，暂时屏蔽，只用于修改密码
//      if( !user.getPassword().equals(tempJson.getString("oldPassword")) ) throw new RuntimeException("旧密码验证失败，请重新输入");
//      if( !user.getPassword().equals(tempJson.getString("password")) ) throw new RuntimeException("新旧密码一致，请重新确认");
//      if( !tempJson.getString("confirmPassword").equals(tempJson.getString("password")) ) throw new RuntimeException("两次密码输入不一致，请重新输入");

        // 公钥 操作员账号 + 随机字符串 加密
        String accessId = user.getOrigin() + ":" + RandomStringUtils.randomAlphanumeric(10);
        user.setAccessId(accessId);
        // 私钥
        String accessKey = MD5Util.encrypt(RandomStringUtils.randomAlphanumeric(16));
        user.setAccessKey(accessKey);
        // 私钥有效期止
        updateUserValidityTime(user, LocalDateTime.now().plusYears(1));

        user.setPassword(tempJson.getString("password"));
        user = userRepository.saveAndFlush(user);

        List<SessionIndexItem> sessionIndexItems = (List<SessionIndexItem>) getBean(SessionIndexManager.class).get(user.getId());
        if (sessionIndexItems != null) {
            Iterator<SessionIndexItem> iterator = sessionIndexItems.iterator();
            while (iterator.hasNext()) {
                SessionIndexItem item = iterator.next();
                getBean(SampleSessionManager.class).removeSession(item.getSessionId());
                iterator.remove();
            }
            if (sessionIndexItems.isEmpty()) getBean(SessionIndexManager.class).remove(user.getId());
            else getBean(SessionIndexManager.class).add(user.getId(), sessionIndexItems);
        }
        return user;
    }

    /***
     * 功能： 新修改密码
     * @param request
     * @return
     */
    public User updatePasswordNew(SimpleRequest request) {
        checkCaptchaApp(request);
        return updatePassword(request);

    }


    /**
     * 功能：查询动态参数测试
     *
     * @param request
     */
    public List<User> findAll(SimpleRequest request) {
        //方法一
        List<Map> filters = request.get("condition");

        //方法二
//        Map row = new HashMap();
//        row.put("name", "测试操作员");
//        row.put("userId", "czy01");
//        Criteria<User> criteria = JpaDsl.toCriteria(row);

        //方法三
//        Criteria<User> criteria = JpaDsl.toCriteria("name", "测试操作员", "userId", "czy01");

        return userRepository.findAll(JpaDsl.toCriteria(filters));
    }


    @Autowired
    EntityManager em;

    public EntityManager getEntityManager() {
        return this.em;
    }

    public List findUser(SimpleRequest request) {
        String sql = "SELECT user0_.id       AS id1_15_," +
                "       user0_.name     AS name2_15_," +
                "       user0_.password AS password3_15_," +
                "       user0_.userid   AS userid4_15_" +
                "  FROM aut_users user0_";
        Query query = em.createNativeQuery(sql);
        // Query 接口是 spring-data-jpa 的接口，而 SQLQuery 接口是 hibenate 的接口，这里的做法就是先转成 hibenate 的查询接口对象，然后设置结果转换器
        query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        return query.getResultList();
    }


    /***
     * 功能： 通过传入的 party 查询对应的User用于Oa动态节点的配置
     * @param party
     * @return
     */
    public String findUserByPartyToString(Party party) {
        List<User> partyList = userRepository.findByParty(party);
        List<String> returnData = new ArrayList<>();
        partyList.stream().forEach(user -> {
            returnData.add(String.valueOf(user.getId()));

        });
        return returnData.toString();
    }

    /***
     * 功能： 通过传入的party数组查询对应的User数组
     * @param parties
     * @return
     */
    public String findUserByPartyToString(List<Party> parties) {
        List<String> returnData = new ArrayList<>();
        parties.stream().map((party -> userRepository.findByParty(party)))
                .forEach(users -> {
                    users.stream().forEach(user -> {
                        returnData.add(String.valueOf(user.getId()));
                    });
                });
        return returnData.toString();
    }

    @Listener(topic = "event:aut.user.findOne")
    public User findOne(SimpleRequest request) {
        return userRepository.findOne((Integer) request.get("id"));
    }

    public List<Post> getPostToApp(SimpleRequest request) {
        String phone = request.get("phone");
        List<User> user = userRepository.findAllByMobileNumber(phone);
        if(user.size() == 0) throw new RuntimeException("用户："+ phone + " 在系统中不存在或被禁用。");
        if(user.size() > 1) throw new RuntimeException("该手机号存在用户: " + user.get(0).getName() +" 与用户: "+ user.get(1).getName() +"同时使用，请核实后联系人资进行修改！可优先使用账号密码方式登录");
        return user.get(0).getPosts();
    }

    public Object getCaptchaApp(SimpleRequest request) {
        String phone = (String) request.get("phone");

        //App 发送手机登录短信接口
        Map map = new HashMap();
        map.put("method", "v1/verification-codes");
        map.put("mobile", phone);
        map.put("type", 1);
        map.put("act", 6);

        String topic = "event:pi.app.synApp";
        JSONObject flg = (JSONObject) EventUtil.sendSynEvent(this, topic, map).stream().findFirst().get();
        return flg;
    }

    /**
     * 功能：通过Name查找用户
     *
     * @param request
     * @return
     */
    public Map loginApp(SimpleRequest request) {
        Map m = request.getMap();
        String phone = (String) m.get("phone");
        List<User> user = userRepository.findAllByMobileNumber(phone);
        if(user.size() == 0) throw new RuntimeException("用户："+ phone + " 在系统中不存在或被禁用。");
        if(user.size() > 1) throw new RuntimeException("该手机号存在用户: " + user.get(0).getName() +" 与用户: "+ user.get(1).getName() +"同时使用，请核实后联系人资进行修改！可优先使用账号密码方式登录");
        Assert.isTrue(!user.get(0).isDisable(), "该用户已禁用");
        // 调用App短信验证平台
        checkCaptchaApp(request);
        return loginCore(request, user.get(0), null);
    }

    /**
     * 功能：手机号码短信验证
     *
     * @param request
     * @return
     */
    public Map loginFlag(SimpleRequest request) {
        // 调用App短信验证平台
        boolean flag = checkCaptchaFlag(request);
        HashMap<String, Object> map = new HashMap<>();
        map.put("flag",flag);
        return map;
    }

    /**
     * 验证短信验证码
     *
     * @param request
     * @return
     */
    public boolean checkCaptchaFlag(SimpleRequest request) {
        String phone = (String) request.get("phone");
        String captcha = (String) request.get("captcha");
        //App 发送手机登录短信接口
        Map map = new HashMap();
        map.put("method", "v1/verification-code/check");
        map.put("mobile", phone);
        map.put("code", captcha);
        map.put("act", 6);
        String topic = "event:pi.app.synApp";
        boolean Flag = true;
        try {
            JSONObject flg = (JSONObject) EventUtil.sendSynEvent(this, topic, map).stream().findFirst().get();
        }catch (Exception e){
            Flag = false;
        }
        return Flag;
    }

    /**
     * 功能：通过Name查找用户
     *
     * @param request
     * @return
     */
    public Map loginTMS(SimpleRequest request) {
        Map m = request.getMap();
        String phone = (String) m.get("phone");
        User user = userRepository.findByMobileNumber(phone);
        if (user == null) throw new RuntimeException("手机号没有绑定操作员");
        Assert.isTrue(!user.isDisable(), "该用户已禁用");
        invoke("tms.chauffeur.loginTMS", m);
//        Post post = postRepository.findOne("YG01null04");//物流司机
        // 调用App短信验证平台
        checkCaptchaApp(request);
        if (user.getPosts().isEmpty()) throw new RuntimeException("操作员没有绑定角色");
        return loginCore(request, user, user.getPosts().get(0));
    }

    /**
     * 验证短信验证码
     *
     * @param request
     * @return
     */
    public Object checkCaptchaApp(SimpleRequest request) {
        String phone = (String) request.get("phone");
        String captcha = (String) request.get("captcha");
        //App 发送手机登录短信接口
        Map map = new HashMap();
        map.put("method", "v1/verification-code/check");
        map.put("mobile", phone);
        map.put("code", captcha);
        map.put("act", 6);
        String topic = "event:pi.app.synApp";
        JSONObject flg = (JSONObject) EventUtil.sendSynEvent(this, topic, map).stream().findFirst().get();
        return flg;
    }

    /**
     * 将全部操作员的手机号和公钥。私钥。私钥有效期一起补全
     *
     * @param request
     */
    public void setPhoneAndAccess(SimpleRequest request) {
        List<User> users = userRepository.findByAccessIdIsNull();
        //批量存储的集合 每五十个
        List data = new ArrayList<>();

        //批量存储
        for (User user : users) {
            if (data.size() == 100) {
                MQUtil.publish("aut.user.funAccess", "批量初始化user的Access", MapUtil.mapper("users", data));
                data.clear();
            }
            data.add(MapUtil.mapped(user));
        }

        if (!data.isEmpty()) {
            MQUtil.publish("aut.user.funAccess", "批量初始化user的Access", MapUtil.mapper("users", data));
        }

    }

    /**
     * 批量插入
     */
    @Consumer(topic = "aut.user.funAccess", backup = false)
    public void fun(SimpleRequest request) {
        List<User> originData = request.getA("users", User.class);
        originData.forEach(user -> {
            user = userRepository.findOne(user.getId());
            // 公钥 操作员账号 + 随机字符串 加密
            String accessId = user.getOrigin() + ":" + RandomStringUtils.randomAlphanumeric(10);
            user.setAccessId(accessId);
            // 私钥
            String accessKey = MD5Util.encrypt(RandomStringUtils.randomAlphanumeric(16));
            user.setAccessKey(accessKey);
            // 私钥有效期止
            updateUserValidityTime(user, LocalDateTime.now().plusYears(1));
            userRepository.save(user);
        });

    }

    /**
     * 更新操作员信息后 将 手机号更新到身份标识和人员档案里
     *
     * @param request
     */
    public void updatePartyIdentification(SimpleRequest request) {
        User user = request.getO(User.class);
        String mobileNumber = user.getMobileNumber();
        if (user.getPerson() == null ) return;
        Party party = user.getPerson().getParty();
        PartyIdentification oldPartyIdentification = partyIdentificationRepository.findFirstByPartyIdTypeAndIdValue("PIT_mobile", mobileNumber);
        if (oldPartyIdentification != null) {
            oldPartyIdentification.setParty(party);
            partyIdentificationRepository.saveAndFlush(oldPartyIdentification);
        } else {
            List<PartyIdentification> partyIdentificationList = partyIdentificationRepository.findByPartyAndPartyIdType(party, "PIT_mobile");
            if (partyIdentificationList.isEmpty()) {
                PartyIdentification partyIdentification = new PartyIdentification();
                partyIdentification.setParty(party);
                partyIdentification.setPartyIdType("PIT_mobile");
                partyIdentification.setIdValue(mobileNumber);
                partyIdentification.setParty(party);
                partyIdentificationRepository.saveAndFlush(partyIdentification);
            } else {
                partyIdentificationList.forEach(partyIdentification -> {
                    partyIdentification.setIdValue(mobileNumber);
                    partyIdentificationRepository.saveAndFlush(partyIdentification);
                });
            }
        }

        JSONObject updateMobile = new JSONObject();
        updateMobile.put("party", party);
        updateMobile.put("mobileNumber", mobileNumber);
        String topic = "event:hr.employee.updateMobile";
        EventUtil.sendSynEvent(this, topic, updateMobile).stream().findFirst();
    }

    /**
     * 清除过期用户会话
     **/
    public void clearExpiredSessions(SimpleRequest request) {
        int size = request.get("size"); /**页大小**/
        int expire = request.get("expire");  /**会话有效时长，单位：小时**/
        long expireDate = DateUtil.add(new Date(), Calendar.HOUR_OF_DAY, -1 * expire).getTime();
        int page = 0;
        while (true) {
            List<Number> userIds = userRepository.findAllUserToId(page, size);
            userIds.stream().forEach(id -> {
                Integer userId = id.intValue();
                List<SessionIndexItem> sessionIndexItems = (List<SessionIndexItem>) getBean(SessionIndexManager.class).get(userId);
                if (sessionIndexItems != null) {
                    Iterator<SessionIndexItem> iterator = sessionIndexItems.iterator();
                    while (iterator.hasNext()) {
                        SessionIndexItem item = iterator.next();
                        if (item.getUpdated() <= expireDate) {
                            getBean(SampleSessionManager.class).removeSession(item.getSessionId());
                            iterator.remove();
                        }
                    }
                    if (sessionIndexItems.isEmpty()) getBean(SessionIndexManager.class).remove(userId);
                    else getBean(SessionIndexManager.class).add(userId, sessionIndexItems);
                }
            });
            page += 1;
            if (userIds.size() < size) break;
        }
    }

    @GetMapping("/killAllUsers")
    @ResponseBody
    @Transactional(rollbackFor = Exception.class)
    public void killAllUsers() {
        int page = 0;
        int size = 500;
        while (true) {
            List<User> users = userRepository.findAllByDisableIsFalseOrderByIdAsc(PageRequest.of(page, size));
            users.stream().forEach(user -> killUser(user));
            page += 1;
            if (users.size() < size) {
                break;
            }
        }
    }

    /**
     * 踢出指定用户
     **/
    public void killUser(User user) {
        List<SessionIndexItem> sessionIndexItems = (List<SessionIndexItem>) getBean(SessionIndexManager.class).get(user.getId());
        if (sessionIndexItems == null) return;
        Iterator<SessionIndexItem> iterator = sessionIndexItems.iterator();
        while (iterator.hasNext()) {
            SessionIndexItem item = iterator.next();
            getBean(SampleSessionManager.class).removeSession(item.getSessionId());
            iterator.remove();
        }
        if (sessionIndexItems.isEmpty()) {
            getBean(SessionIndexManager.class).remove(user.getId());
        } else {
            getBean(SessionIndexManager.class).add(user.getId(), sessionIndexItems);
        }

        String accessKey = MD5Util.encrypt(RandomStringUtils.randomAlphanumeric(16));
        user.setAccessKey(accessKey);
        userRepository.save(user);
    }

    /**
     * 获取所有用户会话
     **/
    public List getSessions(SimpleRequest request) {
        List<Map> result = new ArrayList<>();
        int page = 0;
        int size = 100;
        while (true) {
            List<Number> userIds = userRepository.findAllUserToId(page, size);
            userIds.stream().forEach(id -> {
                Integer userId = id.intValue();
                List<SessionIndexItem> sessionIndexItems = (List<SessionIndexItem>) getBean(SessionIndexManager.class).get(userId);
                if (sessionIndexItems != null) {
                    User user = userRepository.findOne(userId);
                    sessionIndexItems.stream().forEach(sessionIndexItem -> result.add(MapUtil.mapper(
                            "userId", user.getId(),
                            "userName", user.getName(),
                            "sessionId", sessionIndexItem.getSessionId(),
                            "created", DateUtil.timeStampToStr(sessionIndexItem.getCreated()),
                            "updated", DateUtil.timeStampToStr(sessionIndexItem.getUpdated()))));
                }
            });
            page += 1;
            if (userIds.size() < size) break;
        }
        return result;
    }

    /**
     * 清除用户会话
     **/
    public void killSession(SimpleRequest request) {
        String sessionId = request.get("sessionId");
        SimpleSession session = (SimpleSession) getBean(SampleSessionManager.class).getSession(sessionId);
        removeSession(session);
    }

    public void clientRenew() {
        WsMessage wsMessage = new WsMessage();
        wsMessage.setTo(WsMessage.ALL_USER);
        wsMessage.setBody(JSON.toJSONString(MapUtil.mapper("topic", "ws.client.renew")));
        wsPublisher.publish(wsMessage);
    }

    public Page<Map> findAllPartyRoleInner(SimpleRequest request) {
        request = request.getO(SimpleRequest.class);
        Group group = returnGroup(request);
        group.setFilters(group.getFilters().stream().filter(listItem -> {
            return !listItem.getField().equals("inShop");
        }).collect(Collectors.toList()));
        Page<User> userPage = userRepository.findAll(group.build(true), JpaDsl.getPageable(request));

        List<Map> partyRoles = userPage.getContent().stream().map(user -> {
            return MapUtil.mapper("id", user.getPerson().getId(), "name", user.getPerson().getName(),
                    "groupBy","post",
                    "post",user.getPosts().stream().findFirst().get().getName());
        }).collect(Collectors.toList());
        return new PageImpl<>(partyRoles, userPage.getPageable(), userPage.getTotalElements());
    }

    public Page<Map> findAllPartyRoleByOrder(SimpleRequest request) {
        request = request.getO(SimpleRequest.class);
        Group group = JpaDsl.getGroup(request, originGroup -> {
            originGroup.addFilters(JpaDsl.toFilter(
                    "disable", "EQ", false
            ));
            originGroup.addFilters(JpaDsl.toFilter(
                    "person", "NE", null
            ));
            return originGroup;
        });
        group.setFilters(group.getFilters().stream().filter(listItem -> {
            return !listItem.getField().equals("inShop");
        }).collect(Collectors.toList()));
        Page<User> userPage = userRepository.findAll(group.build(true), JpaDsl.getPageable(request));

        List<Map> partyRoles = userPage.getContent().stream().map(user -> {
            return MapUtil.mapper("id", user.getPerson().getId(), "name", user.getPerson().getName());
        }).collect(Collectors.toList());
        return new PageImpl<>(partyRoles, userPage.getPageable(), userPage.getTotalElements());
    }

    private Group returnGroup(SimpleRequest request) {
        return JpaDsl.getGroup(request, originGroup -> {
            Post post = postRepository.findOne(request.getPostId());
            originGroup.addFilters(JpaDsl.toFilter(
                    "posts.branch.id", "EQ", post.getBranch().getId()
            ));
            originGroup.addFilters(JpaDsl.toFilter(
                    "disable", "EQ", false
            ));
            originGroup.addFilters(JpaDsl.toFilter(
                    "person", "NE", null
            ));
            return originGroup;
        });
    }

    @FuncAlias(name = "按角色获取用户")
    public List<String> findUserByPartyRoleId(String partyRoleId) {
        try {
            return userRepository.findByPartyRoleId(partyRoleId).stream().map(user -> String.valueOf(user.getId())).collect(Collectors.toList());
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }

    /**
     * 获取用户名字
     * @param request
     * @return
     */
    public String findNameById(SimpleRequest request) {
        String id = request.get("id");
        if (!id.isEmpty() && !id.equals("null")){
            try {
                return userRepository.findOne(Integer.valueOf(id)) == null ? "--" : userRepository.findOne(Integer.valueOf(id)).getName();
            } catch (Exception e) {
                e.printStackTrace();
                throw e;
            }
        }
        return "--";
    }

    // 获取个人菜单标记
    public List<Object> getPersonalMenuMarks(SimpleRequest request) {
        JSONObject post = request.getJO().getJSONObject("post");
        String terminal = request.getJO().getString("terminal");
        User user = (User)request.getCurrentUser();
        List<PersonalMenuMark> personalMenuMarks = personalMenuMarkRepository.findByPostAndUser(post != null ? post.getString("id") : "", user != null ? user.getId() : null, terminal);
        List<Object> collect = personalMenuMarks.stream().map(personalMenuMark -> {
            return MapUtil.mapped(personalMenuMark.getMenu());
        }).collect(Collectors.toList());
        return collect;
    }

    public Object savePersonalMenuMark(SimpleRequest request) {
        PersonalMenuMark personalMenuMark = request.getO(PersonalMenuMark.class);
        User user = (User)request.getCurrentUser();
        personalMenuMark.setUser(user);
        if (user != null) {
            List<PersonalMenuMark> markList = personalMenuMarkRepository.findByPostAndUserAndMenu(personalMenuMark.getPost().getId(), personalMenuMark.getUser().getId(), personalMenuMark.getMenu().getId());
            if (markList.size() > 0) {
                Boolean mark = personalMenuMark.getMark();
                personalMenuMark=markList.get(0);
                personalMenuMark.setMark(mark);
            } else
                personalMenuMark.setId(SpringManager.getBean(SequenceService.class).getId(PersonalMenuMark.CONST_TABLE_NAME));
            try {
               return personalMenuMarkRepository.saveAndFlush(personalMenuMark);
            } catch (Exception e) {
                throw new RuntimeException("保存菜单标记失败");

            }
        } else {
            return new Object();
        }

    }

    public String findUserByOrigin(SimpleRequest request){
        String origin = request.get("origin");
        User user = userRepository.findByOrigin(origin);
        return user.getMobileNumber();
    }

    //门店信息联系人保存时触发同步任务
    @Listener(topic = "event:contacts.save")
    public void updatePermissions(SimpleRequest request){
        JSONObject jsonObject = request.getJO();
        String id = jsonObject.getJSONObject("contact").getString("id");
        List<Post> managementPost = postRepository.findManagementPost(id);
        if(managementPost != null){
            String code = jsonObject.getString("storeId");
            Store store = storeRepository.findByStoreCode(code);
            PartyRole company = store.getCompany();
            Dept dept = store.getDept();
            List<Location> locations = locationRepository.findLocation(company.getId());
            Set<LocalPermitItem> localPermitItems = new HashSet();
            Enumeration pp_operate = enumerationRepository.findEnumeration("pp_operate");
            Enumeration pp_search = enumerationRepository.findEnumeration("pp_search");
            Enumeration pt_dept = enumerationRepository.findEnumeration("pt_dept");
            Enumeration pt_location = enumerationRepository.findEnumeration("pt_location");
            Enumeration pt_company = enumerationRepository.findEnumeration("pt_company");
            managementPost.forEach((item)->{
                LocalPermit localPermit = localPermitRepository.findLocalPermit(item.getLocalPermit().getId());
                localPermitItems.add(findAllLocalPermitItem(localPermit, company.getId(),company.getName(), pp_operate, pt_company));
                localPermitItems.add(findAllLocalPermitItem(localPermit, dept.getId(), dept.getName(), pp_operate, pt_dept));
                locations.forEach((location->{
                    localPermitItems.add(findAllLocalPermitItem(localPermit, location.getId(), location.getName(), pp_operate, pt_location));
                }));
                localPermitItems.add(findAllLocalPermitItem(localPermit, company.getId(),company.getName(), pp_search, pt_company));
                localPermitItems.add(findAllLocalPermitItem(localPermit, dept.getId(), dept.getName(), pp_search, pt_dept));
                localPermit.getLocalPermitItems().addAll(localPermitItems);
            });
        }
    }

    //门店信息联系人删除时触发同步任务
    @Listener(topic = "event:contacts.delete")
    public void deletePermissions(SimpleRequest request){
        JSONObject jsonObject = request.getJO();
        String id = jsonObject.getJSONObject("contact").getString("id");
        List<Post> managementPost = postRepository.findManagementPost(id);
        if(managementPost != null){
            String code = jsonObject.getString("storeId");
            Store store = storeRepository.findByStoreCode(code);
            PartyRole company = store.getCompany();
            Dept dept = store.getDept();
            List<Location> locations = locationRepository.findLocation(company.getId());
            Enumeration pp_operate = enumerationRepository.findEnumeration("pp_operate");
            Enumeration pp_search = enumerationRepository.findEnumeration("pp_search");
            Enumeration pt_dept = enumerationRepository.findEnumeration("pt_dept");
            Enumeration pt_location = enumerationRepository.findEnumeration("pt_location");
            Enumeration pt_company = enumerationRepository.findEnumeration("pt_company");
            AtomicReference<Boolean> mark = new AtomicReference<>(true);
            managementPost.forEach((item)->{
                LocalPermit localPermit = localPermitRepository.findLocalPermit(item.getLocalPermit().getId());
                localPermitRepository.deleteLocalPermitItem(dept.getId(),pp_operate,pt_dept,localPermit.getId());
                locations.forEach((location->{
                    localPermitRepository.deleteLocalPermitItem(location.getId(),pp_operate,pt_location,localPermit.getId());
                }));
                localPermitRepository.deleteLocalPermitItem(dept.getId(),pp_search,pt_dept,localPermit.getId());
                localPermit.getLocalPermitItems().forEach((localPermitItem -> {
                    List<LocalPermitItem> deptLocalPermitItem= localPermitRepository.findByType(localPermitItem.getId());
                    deptLocalPermitItem.forEach((depts)->{
                        Dept oldDept = deptRepository.findDept(depts.getOrgId());
                        if(oldDept.getCompany().getId().equals(company.getId())){
                            mark.set(false);
                        }
                    });
                }));
                if(mark.get()){
                    localPermitRepository.deleteLocalPermitItem(company.getId(),pp_operate,pt_company,localPermit.getId());
                    localPermitRepository.deleteLocalPermitItem(company.getId(),pp_search,pt_company,localPermit.getId());
                }else {
                    mark.set(true);
                }
            });
        }
    }

    private LocalPermitItem findAllLocalPermitItem(LocalPermit localPermit,String orgId,String orgName,Enumeration purpose,Enumeration type){
        LocalPermitItem localPermitItem = new LocalPermitItem();
        localPermitItem.setLocalPermit(localPermit);
        localPermitItem.setOrgId(orgId);
        localPermitItem.setOrgName(orgName);
        localPermitItem.setPurpose(purpose);
        localPermitItem.setType(type);
        return localPermitItem;
    }


    public List<PartyRole> findAdministrator(SimpleRequest request){
        String storeId = request.get("storeId");
        List<Contacts> contacts = contactsRepository.findByStoreId(storeId);
        List<PartyRole> partyRoles = new ArrayList<>();
        contacts.forEach((item) -> {
            String id = item.getContact().getId();
            User managementUser = userRepository.findManagementUser(id);
            if(managementUser != null){
                String origin = managementUser.getOrigin();
                partyRoles.add(partyRoleRepository.findPartyRole(origin));
            }
        });
        return partyRoles;
    }

    /**
     * 操作员禁用后自动踢出用户（业务事件订阅)
     */
    public void disableKillUser(SimpleRequest request){
        User user = userRepository.findOne(request.getO(User.class).getId());
        killUser(user);
    }

    // 根据 外部编码 获取信息
    public JSONObject accordingOriginQuery(SimpleRequest request) {
        JSONObject param = request.getJO();
        User user = userRepository.findByOrigin(param.getString("ORIGIN"));
        String userStr = JSON.toJSONString(user);
        return JSON.parseObject(userStr);
    }
}

